#ifndef __LOCOMOTIVES_HPP__
#define __LOCOMOTIVES_HPP__

#include "common.h"
#include "electric_motor.hpp"
#include <cmath>
#include <vector>

enum LOCOMOTIVE_TYPE {
    LOCOMOTIVE_TYPE_ELECTRIC,        // 电力机车
    LOCOMOTIVE_TYPE_DIESEL_ELECTRIC, // 柴电机车
    LOCOMOTIVE_TYPE_STEAM            // 蒸汽机车
};
/*
 * 机车的技术参数
 * 不同类型的机车的技术参数都是由这一种结构体进行存储，只不过有的字段为空指针。
 */
class LocomotiveProperty {
public:
    LOCOMOTIVE_TYPE type;     // 机车类型
    std::string locoTypeName; // 机车型号的名称，比如"HXD3C"
    ElectricMotorProperty
        *motorProperty; // 牵引电动机属性，如果是其它类型的机车不一定需要
    fp_type wheelDiameter; // 驱动轮直径 m
    fp_type basicMass; // 机车质量。黏着质量 = 机车质量*（驱动轴数/总轴数）
    int drvAxleNum;     // 驱动轴数
    int axleNum;        // 总轴数
    int motorNum;       // 牵引电机数量
    fp_type startSpeed; // 具备启动牵引力的最大速度 km/h
    fp_type length; // 机车长度，单位为m，一般为车钩中心距。

    LocomotiveProperty(const std::string &locoTypeName, LOCOMOTIVE_TYPE type,
                       fp_type wheelDiameter, fp_type basicMass, int drvAxleNum,
                       int axleNum, int motorNum,
                       ElectricMotorProperty *motorProperty, fp_type startSpeed,
                       fp_type length)
        : locoTypeName(locoTypeName), type(type), wheelDiameter(wheelDiameter),
          basicMass(basicMass), drvAxleNum(drvAxleNum), axleNum(axleNum),
          motorNum(motorNum), motorProperty(motorProperty),
          startSpeed(startSpeed), length(length){};
    // 电力机车/柴电机车-获取电机转矩相关的牵引力限制
    fp_type getMotorTorqueTractionLimit();
};

class Locomotive {
public:
    int id;                 // 机车ID
    std::string name;       // 机车名称
    fp_type additionalMass; //附加配重
    fp_type maxPower; // 最大功率(是根据电机情况等动态算出的)

    Locomotive(int id, const std::string name, LocomotiveProperty *props)
        : id(id), name(name), props(props) {
        this->additionalMass = 0.0;
    };
    virtual ~Locomotive();

    virtual void initialize();
    // 获取机车的长度
    fp_type getLength() { return this->props->length; };
    fp_type mass() { return this->additionalMass + this->props->basicMass; };
    fp_type adhesionMass() {
        return (this->mass()) * (((fp_type)this->props->drvAxleNum) /
                                 ((fp_type)this->props->axleNum));
    };
    fp_type traction(fp_type power, fp_type v, fp_type w_i);
    fp_type tractionLimitAdhesion(fp_type v, fp_type w_i);
    fp_type tractionLimitPower(fp_type power, fp_type v);
    fp_type tractionLimitTorque();
    fp_type speedLimitRPM();
    fp_type friction(fp_type v, fp_type w_i);
    fp_type adhesion_coefficient(fp_type v);

protected:
    LocomotiveProperty *props; // 机车技术参数
};

class ElectricLocomotive : public Locomotive {
private:
    std::vector<ElectricMotor> motors; // 牵引电机

public:
    ElectricLocomotive(int id, const std::string name,
                       LocomotiveProperty *props);
    ~ElectricLocomotive();

    void updateParameters();
};

#endif
